﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services;

using Microsoft.SharePoint.SoapServer;
using System.Xml;
using System.ServiceModel;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using SharePointListSecurity.Model;

namespace SharePointListSecurity.Office
{
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    [WebService(Namespace = "http://schemas.microsoft.com/sharepoint/soap/")]
    public class Lists : Microsoft.SharePoint.SoapServer.Lists
    {
        private SharepointListSecurityService listSecurityService = new SharepointListSecurityService();
        [WebMethod]
        public new SoapXml.SoapXmlElement GetListAndView(string listName, string viewName)
        {
            SoapXml.SoapXmlElement listAndView = base.GetListAndView(listName, viewName);
            try
            {
                SPList currentList = GetListByName(listName);
                var hiddenFields = listSecurityService.GetHiddenFields(currentList, SPControlMode.Edit);
                var readOnlyFields = listSecurityService.GetReadOnlyFields(currentList);

                if (hiddenFields.Count > 0)
                    listAndView.OuterXml = HideFields(hiddenFields, listAndView.OuterXml);

                if (readOnlyFields.Count > 0)
                    listAndView.OuterXml = MakeFieldsReadOnly(readOnlyFields, listAndView.OuterXml);

            }
            catch (Exception)
            {
            }
            return listAndView;
        }

        private string HideFields(IEnumerable<SPField> hiddenFields, string listAndView)
        {
            try
            {
                var filter = String.Join(" or ", hiddenFields.Select(f => String.Format("@Name =\"{0}\"", f.StaticName))
                                                         .ToArray());

                var query = String.Format("//Fields/Field[{0}]", filter);

                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(listAndView);

                var nodes = xmlDocument.SelectNodes(query);
                foreach (XmlNode node in nodes)
                {
                    var parent = node.ParentNode;
                    parent.RemoveChild(node);
                    if (parent.ChildNodes.Count == 0)
                        parent.ParentNode.RemoveChild(parent);
                }

                return xmlDocument.InnerXml;
            }
            catch //(Exception ex)
            {
                return listAndView;
            }

        }

        private string MakeFieldsReadOnly(IEnumerable<SPField> readOnlyFields, string listAndView)
        {
            try
            {
                var filter = String.Join(" or ", readOnlyFields.Select(f => String.Format("@Name =\"{0}\"", f.StaticName))
                                                        .ToArray());

                var query = String.Format("//Fields/Field[{0}]", filter);

                var xmlDocument = new XmlDocument();
                xmlDocument.LoadXml(listAndView);

                var nodes = xmlDocument.SelectNodes(query);
                foreach (XmlNode node in nodes)
                {
                    var attribute = node.Attributes["ReadOnly"];
                    if (attribute == null)
                    {
                        attribute = xmlDocument.CreateAttribute("ReadOnly");
                        node.Attributes.Append(attribute);
                    }
                    attribute.Value = "TRUE";
                }

                return xmlDocument.InnerXml;
            }
            catch //(Exception ex)
            {
                return listAndView;
            }
        }

        private SPList GetListByName(string listName)
        {
            Guid listId;
            if (Guid.TryParse(listName, out listId))
            {
                return SPContext.Current.Web.Lists[listId];
            }
            return SPContext.Current.Web.Lists[listName];
        }

    }
}